﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SiGeSIB.GUI.Common;
using SiGeSIB.Data.Finances;
using SiGeSIB.Services;
using SiGeSIB.Data.Management;
using SiGeSIB.Data.Common;
using SiGeSIB.Data.Security;

namespace SiGeSIB.GUI.Finances
{
#if DESIGN
	public partial class FEditMovimentation : FormRedirector.FEditMovimentation
#else
	public partial class FEditMovimentation : FGenericEditor<Movimentation>
#endif
	{
		#region Constructor(s)
		public FEditMovimentation()
			: this(EFormState.View, EMovimentationType.Income, -1)
		{ }
		public FEditMovimentation(EFormState initialState, EMovimentationType type, int id)
			: base(initialState, id)
		{
			InitializeComponent();

			#region Inicializando o tipo da tela
			if (type == EMovimentationType.Income)
			{
				if (initialState == EFormState.View)
				{
					this.Text = "Edição de entrada";
					_IdleMessage = "Visualize as informações da entrada.";
				}
				else
				{
					this.Text = "Inserção de entrada";
					_IdleMessage = "Insira as informações da entrada.";
				}

				lblContributor.Text = "Origem:";
			}
			else if (type == EMovimentationType.Outcome)
			{
				if (initialState == EFormState.View)
				{
					this.Text = "Edição de saída";
					_IdleMessage = "Visualize as informações da saída.";
				}
				else
				{
					this.Text = "Inserção de saída";
					_IdleMessage = "Insira as informações da saída.";
				}

				lblContributor.Text = "Beneficiado:";

				lblIncomeType.Visible = cboIncomeType.Visible = false;
			}
			else
			{
				this.Text = "Edição de lançamento futuro";
				_IdleMessage = "Visualize as informações do lançamento futuro.";
			}
			#endregion

			#region Members Step
			InitialState = initialState;
			Type = type;
			CurrentId = id; 
			#endregion

			#region ErrorController
			_Controller.AddErrorLabel("InvalidValue", new Control[] { lblValue, nudValue });
			_Controller.AddErrorLabel("InvalidCheck", new Control[] { lblCheckNumber, txtCheckNumber });
			_Controller.AddErrorLabel("RequiredDate", new Control[] { lblMovimentationDate, dtpMovimentationDate });
			_Controller.AddErrorLabel("RequiredCostCenter", new Control[] { lblCostCenter, cboCostCenter });
			_Controller.AddErrorLabel("RequiredContributor", new Control[] { lblContributor, cboContributor });
			#endregion

			#region FieldsToLock
			FieldsToLock = new List<object>()
			{
				lblCheckNumber,
				lblContributor,
				lblCostCenter,
				lblDescription,
				lblMovimentationDate,
				lblPaymentMethod,
				lblValue,
				lblIncomeType,
				cboContributor,
				cboCostCenter,
				cboPaymentMethod,
				cboIncomeType,
				dtpMovimentationDate,
				nudValue,
				txtCheckNumber,
				txtDescription
			};
			#endregion
		}
		#endregion

		#region Properties
		public EMovimentationType Type { get; set; }
		public int CurrentId { get; set; }
		public Movimentation EditedItem { get; private set; }

		protected override bool HasEditPermission
		{
			get
			{
				return
					Manager.Instance.LoggedUser.IsAdmin
					||
					(
						Manager.Instance.LoggedUser.Permissions
						&
						EPermissions.ManageMovimentation
					) != EPermissions.None;
			}
		}
		#endregion

        #region Methods
        #region Auxiliares
        private void _FillPaymentMethods()
        {
            List<KeyValuePair<string, EPaymentMethod>> methods = new List<KeyValuePair<string, EPaymentMethod>>();

            foreach (EPaymentMethod type in Enum.GetValues(typeof(EPaymentMethod)))
                methods.Add(new KeyValuePair<string, EPaymentMethod>(type.GetDescription(), type));

            cboPaymentMethod.DisplayMember = "Key";
            cboPaymentMethod.ValueMember = "Value";
            cboPaymentMethod.DataSource = methods;
        }

		private void _FillContributorsCombo(List<Contributor> contributors)
        {
            List<KeyValuePair<int, string>> contNames = new List<KeyValuePair<int, string>>();

            if (!contributors.IsNullOrEmpty())
                foreach (Contributor contributor in contributors)
                    contNames.Add(new KeyValuePair<int, string>(contributor.Id, contributor.Name));

            cboContributor.ValueMember = "Key";
            cboContributor.DisplayMember = "Value";
            cboContributor.DataSource = contNames;
			cboContributor.SelectedIndex = -1;
        }

        private void _FillCostCentersCombo(List<CostCenter> costCenters)
        {
            List<KeyValuePair<int, string>> cost = new List<KeyValuePair<int, string>>();

            if (!costCenters.IsNullOrEmpty())
                foreach (CostCenter c in costCenters)
					cost.Add(new KeyValuePair<int, string>(c.Id, c.Name));

            cboCostCenter.ValueMember = "Key";
            cboCostCenter.DisplayMember = "Value";
			cboCostCenter.DataSource = cost;
			cboCostCenter.SelectedIndex = -1;
		}

		private void _FillIncomeTypeCombo()
		{
			List<KeyValuePair<string, EIncomeType>> types = new List<KeyValuePair<string, EIncomeType>>();

			foreach (var item in (EIncomeType[])(Enum.GetValues(typeof(EIncomeType))))
			{
				types.Add(new KeyValuePair<string, EIncomeType>(item.GetDescription(), item));
			}

			cboIncomeType.ValueMember = "Value";
			cboIncomeType.DisplayMember = "Key";
			cboIncomeType.DataSource = types;
		}
        #endregion

        #region Overridens
        protected override void OnLoad(EventArgs e)
        {
			_FillPaymentMethods();

            base.OnLoad(e);
        }

        public override bool ConflictsWith(ConflictableForm form)
        {
            bool conflicts = false;

            if (form.GetType() == this.GetType())
            {
                // Só conflita se for inserção ou se for edição do mesmo elemento
                FEditMovimentation fEdit = form as FEditMovimentation;

                if (fEdit.InitialState == this.InitialState)
                {
                    if (this.InitialState == EFormState.Edit)
                        conflicts = true;
                    else if (this.EditedItem != null && fEdit.EditedItem != null && this.EditedItem.Id == fEdit.EditedItem.Id)
                        conflicts = true;
                }
            }

            return conflicts;
        }

		#region Loading
		protected override Movimentation _LoadEntity(int id)
		{
			IFinancesServicesProvider finProv = Manager.Instance.ServicesProvider.CreateFinancesServicesProvider();

			Movimentation mov = id > 0 ? finProv.GetMovimentation(id) : null;

			return mov;
		}

		protected override void _FillEntity(Movimentation entity)
		{
			if (entity != null)
			{
				_Id = entity.Id;

				nudValue.Value = entity.Amount;
				cboPaymentMethod.SelectedValue = entity.PaymentMethod.Method;
				txtCheckNumber.Text = entity.PaymentMethod.CheckNumber;
				dtpMovimentationDate.Value = entity.MovimentationDate;
				cboCostCenter.SelectedValue = entity.CostCenterId;
				cboContributor.SelectedValue = entity.ContributorId;
				txtDescription.Text = entity.Observation;

				if (entity.Type == EMovimentationType.Income)
				{
					Income income = entity as Income;

					cboIncomeType.SelectedValue = income.IncomeType;
				}
			}
		}

		protected override object _LoadSpecificData()
		{
			IManagementServicesProvider manProv = Manager.Instance.ServicesProvider.CreateManagementServicesProvider();
			List<Contributor> contributors = manProv.GetContributors(null);

			IFinancesServicesProvider finProv = Manager.Instance.ServicesProvider.CreateFinancesServicesProvider();
			List<CostCenter> costCenters = finProv.GetCostCenters(CostCenterInfo.GeneralData);

			return new object[] { contributors, costCenters };
		}

        protected override void _FillSpecificData(object result)
        {
            if (!_AlreadyLoaded)
            {
                _AlreadyLoaded = true;

                List<Contributor> contributors = ((object[])result)[0] as List<Contributor>;
                _FillContributorsCombo(contributors);

                List<CostCenter> costCenters = ((object[])result)[1] as List<CostCenter>;
                _FillCostCentersCombo(costCenters);

				if (Type == EMovimentationType.Income)
					_FillIncomeTypeCombo();
            }
        }
		#endregion

		#region Commit
		protected override Movimentation _BuildEntity()
		{
			Movimentation movimentation = Movimentation.Create(Type);

			movimentation.Id = _Id;

			movimentation.Amount = Math.Abs(nudValue.Value);
			movimentation.PaymentMethod.Method = (EPaymentMethod)cboPaymentMethod.SelectedValue;
			movimentation.PaymentMethod.CheckNumber = ((EPaymentMethod)cboPaymentMethod.SelectedValue == EPaymentMethod.Check) ? txtCheckNumber.Text : null;
			movimentation.MovimentationDate = dtpMovimentationDate.Value.Truncate();

			if (cboCostCenter.SelectedValue != null)
				movimentation.CostCenterId = (int)cboCostCenter.SelectedValue;

			if (cboContributor.SelectedValue != null)
				movimentation.ContributorId = (int)cboContributor.SelectedValue;

			movimentation.Observation = txtDescription.Text;

			if (Type == EMovimentationType.Income)
			{
				((Income)movimentation).IncomeType = (EIncomeType)cboIncomeType.SelectedValue;
			}

			return movimentation;
		}

		protected override ExceptionsContainer _ValidateEntity(Movimentation entity)
		{
			ExceptionsContainer ex = new ExceptionsContainer();

			if (entity.Amount < 0)
				ex.Add(new ValidationError("InvalidValue", "O valor da movimentação não pode ser negativo."));

			if (entity.PaymentMethod.Method == EPaymentMethod.Check && entity.PaymentMethod.CheckNumber == null)
				ex.Add(new ValidationError("InvalidCheck", "O cheque necessita de um número."));

			if (entity.MovimentationDate.HasInvalidValue())
				ex.Add(new ValidationError("RequiredDate", "Data é um campo obrigatório."));

			if (entity.CostCenterId <= 0)
				ex.Add(new ValidationError("RequiredCostCenter", "Centro de custo é um campo obrigatório."));

			if (entity.ContributorId <= 0)
				ex.Add(new ValidationError("RequiredContributor", "Contribuinte é um campo obrigatório."));

			return ex;
		}

		protected override int _SaveEntity(Movimentation entity)
		{
			IFinancesServicesProvider finProv = Manager.Instance.ServicesProvider.CreateFinancesServicesProvider();
			int id = entity.Id;

			if (entity.Id > 0)
				finProv.UpdateMovimentation(entity);
			else
				id = finProv.InsertMovimentation(entity);

			return id;
		}  
		#endregion
        #endregion
        #endregion

        #region EventHandlers
        private void cboPaymentMethod_SelectedValueChanged(object sender, EventArgs e)
        {
            EPaymentMethod method = cboPaymentMethod.SelectedValue != null ? ((EPaymentMethod)cboPaymentMethod.SelectedValue) : EPaymentMethod.Unknown;

            switch (method)
            {
                case EPaymentMethod.Check:
                    lblCheckNumber.Visible = true;
                    txtCheckNumber.Visible = true;
                    break;
                default:
                    lblCheckNumber.Visible = false;
                    txtCheckNumber.Visible = false;
                    break;
            }
        } 

        #endregion
    }
}
